<?php
/**
 * Created by lni_wang.
 * Product: PhpStorm
 * Date: 2017/4/16 14:37
 * File: Oauth_model.php
 */
class Oauth_model extends MY_Model
{
    public function get_code(array $params)
    {
        data_filter($params);
        if(empty($params['app_id'])){
            throw new SysException(30003, ['app_id']);
        }

        $info = $this->get_row('certificate', [
            'app_id'     => $params['app_id'],
        ]);

        if(empty($info) || !isset($info['user_id'])){
            throw new SysException(40004);
        }

        $access_token = [
            'user_id'       => $info['user_id'],
            'access_toekn'  => bin2hex(openssl_random_pseudo_bytes(32)),
            'refresh_token' => bin2hex(openssl_random_pseudo_bytes(32)),
            'code'          => bin2hex(openssl_random_pseudo_bytes(32)),
            'expires_in'    => date("Y-m-d H:i:s", strtotime("+2 hours")),
            'status'        => 10,
        ];

        $result = $this->insert('access_token', $access_token);

        if($result === false){
            throw new SysException(30004);
        }

        $this->clear_code($access_token['user_id']);
        return [
            'code' => $access_token['code']
        ];
    }

    /**
     * 清除30分钟内未认证的code
     * @param $user_id
     *
     * @return mixed
     */
    private function clear_code($user_id)
    {
        return $this->db_delete('access_token', [
            'user_id'        => $user_id,
            'status'         => 10,
            'create_time < ' => date("Y-m-d H:i:s", strtotime("-30 minutes")),
        ]);
    }

    public function get_access_token_by_code(array $params)
    {
        data_filter($params);
        if(empty($params['code'])){
            throw new SysException(30003, ['code']);
        }
        if(empty($params['app_secret'])){
            throw new SysException(30003, ['app_secret']);
        }
        #根据code 查找用户信息
        $access_token = $this->get_row('access_token', [
            'code'           => $params['code'],
            'status'         => 10,
            'create_time >=' => date("Y-m-d H:i:s", strtotime("-30 minutes")),
        ]);

        if(empty($access_token) || empty($access_token['user_id'])){
            throw new SysException(40004);
        }

        #根据用户信息查找z证书
        $certificate = $this->get_row('certificate', [
            'user_id' => $access_token['user_id']
        ]);

        #比较
        if($certificate['app_secret'] != $params['app_secret']){
            throw new SysException(40005);
        }

        $expires_in = date("Y-m-d H:i:s", strtotime("+2 hours"));
        $result = $this->update('access_token', [
            'status'     => 20,
            'code'       => '',
            'expires_in' => $expires_in,
        ], [
            'code' => $access_token['code']
        ]);

        if($result === false){
            throw new SysException(30004);
        }

        $this->save_access_token_to_cache([
            'access_token'  => $access_token['access_token'],
            'refresh_token' => $access_token['refresh_token'],
            'expires_in'    => $expires_in,
            'user_id'       => $access_token['user_id'],
        ]);

        return [
            'access_token'  => $access_token['access_token'],
            'refresh_token' => $access_token['refresh_token'],
            'expires_in'    => $expires_in,
        ];

    }

    public function get_access_token_by_refresh_token(array $params)
    {
        data_filter($params);
        if(empty($params['refresh_token'])){
            throw new SysException(30003, ['refresh_token']);
        }
        $access_token = $this->get_row('access_token', [
            'refresh_token' => $params['refresh_token']
        ]);

        if(empty($access_token)){
            throw new SysException(30005);
        }

        $new_access_token = [
            'access_token'  => bin2hex(openssl_random_pseudo_bytes(32)),
            'refresh_token' => bin2hex(openssl_random_pseudo_bytes(32)),
            'expires_in'    => date("Y-m-d H:i:s", strtotime("+2 hours")),
        ];

        $this->clear_cache('access_token', $access_token['access_token']);
        $this->save_access_token_to_cache([
            'access_token'  => $new_access_token['access_token'],
            'refresh_token' => $new_access_token['refresh_token'],
            'expires_in'    => $new_access_token['expires_in'],
            'user_id'       => $access_token['user_id'],
        ]);

        $result = $this->update('access_token', $new_access_token, [
            'refresh_token' => $params['refresh_token']
        ]);
        if($result === false){
            throw new SysException(30004);
        }

        return $new_access_token;
    }

    private function save_access_token_to_cache(array $params)
    {
        data_filter($params);
        if(empty($params['access_token'])){
            throw new SysException(30003, ['access_token']);
        }
        if(empty($params['refresh_token'])){
            throw new SysException(30003, ['refresh_token']);
        }
        if(empty($params['expires_in'])){
            throw new SysException(30003, ['expires_in']);
        }
        if(empty($params['user_id'])){
            throw new SysException(30003, ['user_id']);
        }

        $this->insert_cache('access_token', $params['access_token'], [
            'access_token'  => $params['access_token'],
            'refresh_token' => $params['refresh_token'],
            'expires_in'    => $params['expires_in'],
            'user_id'       => $params['user_id'],
        ]);
    }

    public function check_access_token(array $params)
    {
        data_filter($params);
        if(!isset($params['access_token'])){
            throw new SysException(30003, ['access_token']);
        }
        $access_token = $this->get_cache('access_token', $params['access_token']);
        if(empty($access_token)){
            $access_token = $this->get_row('access_token', [
                'access_token' => $params['access_token']
            ]);
        }

        if(empty($access_token)){
            throw new SysException(40005);
        }

        if(strtotime($access_token['expires_in']) <= time()){
            throw new SysException(40006);
        }

        return [
            'user_id' => $access_token['user_id']
        ];
    }
}